package communication;

import model.FirstOrderInvertedPendulumSystem;
import model.Massage;
import util.ConversionUtil;
import util.DrawUtil;

import java.io.*;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @author wujiazhan
 * @className ClientThread
 * @description 服务器线程类
 * @date 2021-06-08 1:10
 */
@SuppressWarnings("all")
public class ServerThread implements Runnable{
    //服务端端所在计算机ip地址
    private String ip;
    private Socket socket;
    private double x_target;
    private boolean is_start;//是否启动
    private final Object writeThread_lock = new Object();//写线程锁
    private final Object plot_lock = new Object();//画图线程锁
    private final Object tar_lock = new Object();//变量锁
    private boolean is_plot = true;
    private List<Massage> list;


    public ServerThread(Socket accept) throws IOException {
        this.socket = accept;
        this.x_target = 0.0;
        this.ip = "";
        this.is_start = false;
        list = new ArrayList<Massage>();
    }


    //创建模型对象
    FirstOrderInvertedPendulumSystem system = new FirstOrderInvertedPendulumSystem(0.002);

    //写数据数据线程
    Thread writeThread = new Thread(new Runnable() {
        @Override
        public void run() {
            OutputStream out = null;
            DataOutputStream dOut = null;
            try {
                //线程阻塞，等待读数据的线程唤醒\
                synchronized (writeThread_lock){
                    writeThread_lock.wait();
                }
                out = socket.getOutputStream();
                dOut = new DataOutputStream(out);
                byte[] bytes = null;
                double[] res = new double[2];
                while (true) {
                    synchronized (tar_lock){
                        system.run(x_target);
                    }
                    res[0] = system.getX_car();
                    res[1] = system.getTheta();
                    String string = Arrays.toString(res);
                    bytes = ConversionUtil.asByteArray(res);
                    System.out.println(Arrays.toString(ConversionUtil.asDoubleArray(bytes)));
                    if(list.size() < 10000){
                        Massage massage = new Massage(res[0], res[1],system.getX_target());
                        list.add(massage);
                    }else {
                        if(is_plot){
                            synchronized (plot_lock){
                                plot_lock.notify();
                            }
                            is_plot = false;
                        }
                    }
                    Thread.sleep(2);
                    dOut.write(string.substring(1, string.length() - 1).getBytes());
                }
            } catch (IOException e) {
                e.printStackTrace();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    });
    //读数据线程
    Thread readThread = new Thread(new Runnable() {
        @Override
        public void run() {
            InputStream in = null;
            DataInputStream din = null;
            try{
                in = socket.getInputStream();
                din = new DataInputStream(in);
                //打印服务端相关信息
                ip = socket.getInetAddress().toString();
                ip = ip.substring(ip.indexOf("/") + 1);
                byte[] bytes = new byte[20];
                int len = 0;
                while (true) {
                        //当返回值为-1的时候说明读取完数据
                        while ((len = din.read(bytes)) != -1) {
                            String s = new String(bytes,0,len);
                            Double arr = Double.parseDouble(s);
                            System.out.println("[" + ip + "]" + ":" + arr);
                            if (arr != null) {
                                synchronized (tar_lock){
                                    x_target = arr;
                                }
                                if(! is_start){
                                    //收到数据后，唤醒写数据线程
                                    synchronized (writeThread_lock){
                                        writeThread_lock.notify();
                                    }
                                    is_start = true;
                                }
                            }
                        }
                    }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    });

    Thread drawThread = new Thread(new Runnable() {
        @Override
        public void run() {
            synchronized (plot_lock){
                try {
                    plot_lock.wait();
                    DrawUtil.plot(list,0.002);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

        }
    });

    @Override
    public void run() {
        //开启画图线程
        drawThread.start();
        //开启读数据线程
        readThread.start();
        //开启写数据线程
        writeThread.start();
    }
}
